package cn.xfdtool.slowsql.processor;

import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.core.util.ObjectUtil;
import cn.xfdtool.slowsql.config.SlowSQLConfig;
import cn.xfdtool.slowsql.dto.SlowSQLDTO;
import cn.xfdtool.slowsql.dto.SlowSQLNotifyDTO;
import cn.xfdtool.slowsql.listener.SlowSQLMatchListener;
import cn.xfdtool.slowsql.listener.SlowSQLNotifyListener;
import cn.xfdtool.slowsql.listener.SlowSQLParserListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.*;

/**
 * 慢SQL处理器, 用于慢SQL处理
 *
 * @author xfd
 * 2022/5/14
 */
@Slf4j
public class SlowSQLProcessor implements InitializingBean, DisposableBean {

    /** 慢SQL处理队列 */
    private final LinkedBlockingQueue<SlowSQLDTO> slowSQLQueue = new LinkedBlockingQueue<SlowSQLDTO>();

    /** 调度线程池 */
    private ScheduledExecutorService scheduledExecutorService;

    /** 单个调度器 */
    private ScheduledFuture<?> scheduledFuture;

    @Autowired
    private SlowSQLConfig slowSQLConfig;

    @Autowired
    private SlowSQLMatchListener slowSQLMatchListener;

    @Autowired
    private SlowSQLParserListener slowSQLParserListener;

    @Autowired
    private SlowSQLNotifyListener slowSQLNotifyListener;

    /**
     * 慢SQL对象添加
     * @param slowSQLDTO
     */
    public void addSlowSQLDTO(SlowSQLDTO slowSQLDTO) {
        if (this.slowSQLMatchListener.isMatch(slowSQLDTO)) {
            slowSQLQueue.add(slowSQLDTO);
        }
    }

    /**
     * 报告慢SQL
     */
    protected void reportSlowSQL() {
        SlowSQLDTO slowSQLDTO = this.slowSQLQueue.poll();
        if (ObjectUtil.isNull(slowSQLDTO)) {
            return;
        }
        // 执行处理
        SlowSQLNotifyDTO slowSQLNotifyDTO = this.slowSQLParserListener.parse(slowSQLDTO);
        this.slowSQLNotifyListener.notify(slowSQLNotifyDTO);
        slowSQLDTO = null;
        slowSQLNotifyDTO = null;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.scheduledExecutorService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("xfdtool-slowsql-task", false));
        this.scheduledFuture = this.scheduledExecutorService.scheduleAtFixedRate(() -> {
            try {
                // 执行解析
                reportSlowSQL();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }, 1000, this.slowSQLConfig.getSlowSQLParseTime(), TimeUnit.MILLISECONDS);
    }
    @Override
    public void destroy() throws Exception {
        if (this.scheduledFuture != null) {
            this.scheduledFuture.cancel(true);
            this.scheduledFuture = null;
        }
        if (this.scheduledExecutorService != null) {
            this.scheduledExecutorService.shutdownNow();
            this.scheduledExecutorService = null;
        }
    }
}
